package com.king.service;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author king
 * @date 2020/12/21 17:49
 */
public class NettyService {
    public static void main(String[] args) {
        /**
         * 新建两个线程组，Boss线程组启动一条线程，监听 OP_ACCEPT 事件
         * Worker 线程组默认启动 CPU 核数*2 的线程
         * 监听客户端连接的 OP_READ 和 OP_WRITE 事件， 处理 I/O 事件
         */
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // ServerBootstrap 为 Netty 服务启动辅助类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);

            // 设置 TCP Socket 通道为 NioServerSocketChannel
            // 若是 UDP 通信， 则将其设置为 DatagramChannel
            serverBootstrap.channel(NioServerSocketChannel.class);

            // 设置一些 TCP 参数
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128)
                    /**
                     * 当有客户端链路注册读写事件时，初始化 Handler
                     * 并将 Handler 加入管道中
                     */
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        /**
                         * 向 Worker 线程的管道双向链表中添加处理类 ServerHandler
                         * 整个处理流向如下：HeadContext-channelRead 读数据 --> ServerHandler-channelRead
                         * 读取数据进行业务逻辑判断，最后将结果返回给客户端 --> TailContext-write --> HeadContext-write
                         */
                        @Override
                        protected void initChannel(SocketChannel sc) throws Exception {
                            sc.pipeline().addLast(new ServerHandler());
                        }
                    });

            // 同步绑定端口
            ChannelFuture future = serverBootstrap.bind(8080).sync();

            // 阻塞主线程，直到 Socket 通道被关闭
            future.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 最终关闭线程组
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
